///*
// * Copyright 2015, gRPC Authors All rights reserved.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *     http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package keter.lab.grpc.routeguide;
//
//import io.grpc.Server;
//import io.grpc.ServerBuilder;
//import io.grpc.examples.routeguide.*;
//import io.grpc.stub.StreamObserver;
//
//import java.io.IOException;
//import java.net.URL;
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.Collections;
//import java.util.List;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.concurrent.ConcurrentMap;
//import java.util.logging.Logger;
//
//import static java.lang.Math.*;
//
///**
// * A sample gRPC server that serve the RouteGuide (see route_guide.proto) service.
// */
//public class RouteGuideServer {
////  private static final Logger logger = org.slf4j.LoggerFactory.getLogger(RouteGuideServer.class);
//  private static final Logger logger = Logger.getLogger(RouteGuideServer.class.getName());
//
//  private final int port;
//  private final Server server;
//
//  public RouteGuideServer(int port) throws IOException {
//    this(port, RouteGuideUtil.getDefaultFeaturesFile());
//  }
//
//  /** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */
//  public RouteGuideServer(int port, URL featureFile) throws IOException {
//    this(ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile));
//  }
//
//  /** Create a RouteGuide server using serverBuilder as a base and features as data. */
//  public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
//    this.port = port;
//    server = serverBuilder.addService(new RouteGuideService(features))
//        .build();
//  }
//
//  /** Start serving requests. */
//  public void start() throws IOException {
//    server.start();
//    logger.info("Server started, listening on " + port);
//    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//      // Use stderr here since the logger may has been reset by its JVM shutdown hook.
//      System.err.println("*** shutting down gRPC server since JVM is shutting down");
//      RouteGuideServer.this.stop();
//      System.err.println("*** server shut down");
//    }));
//  }
//
//  /** Stop serving requests and shutdown resources. */
//  public void stop() {
//    if (server != null) {
//      server.shutdown();
//    }
//  }
//
//  /**
//   * Await termination on the main thread since the grpc library uses daemon threads.
//   */
//  private void blockUntilShutdown() throws InterruptedException {
//    if (server != null) {
//      server.awaitTermination();
//    }
//  }
//
//  /**
//   * Main method.  This comment makes the linter happy.
//   */
//  public static void main(String[] args) throws Exception {
//    RouteGuideServer server = new RouteGuideServer(8980);
//    server.start();
//    server.blockUntilShutdown();
//  }
//
//  /**
//   * Our implementation of RouteGuide service.
//   *
//   * <p>See route_guide.proto for details of the methods.
//   */
//  private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
//    private final Collection<Feature> features;
//    private final ConcurrentMap<Point, List<RouteNote>> routeNotes =
//        new ConcurrentHashMap<Point, List<RouteNote>>();
//
//    RouteGuideService(Collection<Feature> features) {
//      this.features = features;
//    }
//
//    /**
//     * Gets all features contained within the given bounding {@link Rectangle}.
//     *
//     * @param request the bounding rectangle for the requested features.
//     * @param responseObserver the observer that will receive the features.
//     */
//    @Override
//    public void listFeatures(Rectangle request, StreamObserver<Feature> responseObserver) {
//      int left = min(request.getLo().getLongitude(), request.getHi().getLongitude());
//      int right = max(request.getLo().getLongitude(), request.getHi().getLongitude());
//      int top = max(request.getLo().getLatitude(), request.getHi().getLatitude());
//      int bottom = min(request.getLo().getLatitude(), request.getHi().getLatitude());
//
//      for (Feature feature : features) {
//        if (!RouteGuideUtil.exists(feature)) {
//          continue;
//        }
//
//        int lat = feature.getLocation().getLatitude();
//        int lon = feature.getLocation().getLongitude();
//        if (lon >= left && lon <= right && lat >= bottom && lat <= top) {
//          responseObserver.onNext(feature);
//        }
//
//        try {
//          logger.info("模拟服务器暂停行为。。。");
//          Thread.sleep(2000);
//        } catch (InterruptedException e) {
//          e.printStackTrace();
//        }
//
//      }
//      responseObserver.onCompleted();
//    }
//
//      /**
//     * Get the notes list for the given location. If missing, create it.
//     */
//    private List<RouteNote> getOrCreateNotes(Point location) {
//      List<RouteNote> notes = Collections.synchronizedList(new ArrayList<RouteNote>());
//      List<RouteNote> prevNotes = routeNotes.putIfAbsent(location, notes);
//      return prevNotes != null ? prevNotes : notes;
//    }
//
//    /**
//     * Gets the feature at the given point.
//     *
//     * @param location the location to check.
//     * @return The feature object at the point. Note that an empty name indicates no feature.
//     */
//    private Feature checkFeature(Point location) {
//      for (Feature feature : features) {
//        if (feature.getLocation().getLatitude() == location.getLatitude()
//            && feature.getLocation().getLongitude() == location.getLongitude()) {
//          return feature;
//        }
//      }
//
//      // No feature was found, return an unnamed feature.
//      return Feature.newBuilder().setName("").setLocation(location).build();
//    }
//
//    /**
//     * Calculate the distance between two points using the "haversine" formula.
//     * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
//     *
//     * @param start The starting point
//     * @param end The end point
//     * @return The distance between the points in meters
//     */
//    private static int calcDistance(Point start, Point end) {
//      double lat1 = RouteGuideUtil.getLatitude(start);
//      double lat2 = RouteGuideUtil.getLatitude(end);
//      double lon1 = RouteGuideUtil.getLongitude(start);
//      double lon2 = RouteGuideUtil.getLongitude(end);
//      int r = 6371000; // meters
//      double phi1 = toRadians(lat1);
//      double phi2 = toRadians(lat2);
//      double deltaPhi = toRadians(lat2 - lat1);
//      double deltaLambda = toRadians(lon2 - lon1);
//
//      double a = sin(deltaPhi / 2) * sin(deltaPhi / 2)
//          + cos(phi1) * cos(phi2) * sin(deltaLambda / 2) * sin(deltaLambda / 2);
//      double c = 2 * atan2(sqrt(a), sqrt(1 - a));
//
//      return (int) (r * c);
//    }
//  }
//}
